#include "Scene.h"

namespace egg{

    Scene::Scene(){
        mRenderer=Renderer::getSingletonPtr();
        mRootActor=new RootActor(this);
    }

    void Scene::runFrame(){
        update();
        render();
    }

    void Scene::addLight(Light* _light){
        mLights.push_back(_light);
    }

    void Scene::addCamera(Camera* _camera){
        mCameras.push_back(_camera);
    }

    void Scene::addBoundingUpdateListener(Actor* _actor){
        mBoundingDirtyCache.addActor(_actor);
    }

    void Scene::addTransformUpdateListener(Actor* _actor){
        mTransformDirtyCache.addActor(_actor);
    }

    void Scene::addFrameEndListener(Actor* _actor){
        mFrameEndListeners.push_back(_actor);
    }

    void Scene::addFrameBeginListener(Actor* _actor){
        mFrameBeginListeners.push_back(_actor);
    }

    //=================================================================

    void Scene::update(){
        for(uint32 i=0;i<mFrameBeginListeners.size();i++)
            mFrameBeginListeners[i]->onFrameBegin(mFrameEvent);
        mTransformDirtyCache.update();
        mBoundingDirtyCache.update();
        mTransformDirtyCache.clear();
        mBoundingDirtyCache.clear();
        for(uint32 i=0;i<mFrameEndListeners.size();i++)
            mFrameEndListeners[i]->onFrameEnd(mFrameEvent);
    }

    void Scene::render(){
        sortCameras();
        list<Camera*>::iterator itr=mOrderedCameras.begin();
        for(;itr!=mOrderedCameras.end();itr++){
            mRenderer->renderBegin();
            visibleCull(*itr);
            mRenderer->render(*itr);
            mRenderer->renderEnd();
        }
    }

    void Scene::sortCameras(){
        mMaxViewWidth=0;
        mMaxViewHeight=0;
        mOrderedCameras.clear();
        for(uint32 i=0;i<mCameras.size();i++){
            if(mCameras[i]->getViewport()->isRenderToWindow()){
                mOrderedCameras.push_back(mCameras[i]);
            }else{
                mOrderedCameras.push_front(mCameras[i]);
            }
            //get the max viewport size
            mMaxViewWidth=max(
                mMaxViewWidth,
                mCameras[i]->getViewport()->getRight());
            mMaxViewHeight=max(
                mMaxViewHeight,
                mCameras[i]->getViewport()->getTop());
        }
        gRenderTargetGroup->reserve(mMaxViewWidth,mMaxViewHeight);
    }

    void Scene::visibleCull(Camera* _camera){
        static vector<Actor*> actorStack;
        actorStack.clear();
        actorStack.push_back(mRootActor);
        while(actorStack.size()){
            Actor* actor=actorStack.back();
            actor->onRendering(mRenderer);
            vector<Actor*>& children=actor->getChildren();
            actorStack.pop_back();
            for(int i=0;i<children.size();i++){
                actorStack.push_back(children[i]);
            }
        }

        for(uint32 i=0;i<mLights.size();i++)
            mRenderer->addLight(mLights[i]);
    }

}